package top.lixunda.ecommerce.server.good.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.common.utils.StringUtils;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.QiNiuCallbackBody;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheAdminUser;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStore;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheStoreUser;
import top.lixunda.ecommerce.server.business.api.entity.dto.PageDTO;
import top.lixunda.ecommerce.server.good.api.entity.db.*;
import top.lixunda.ecommerce.server.good.api.entity.dto.*;
import top.lixunda.ecommerce.server.good.api.entity.vo.GoodGroupVO;
import top.lixunda.ecommerce.server.good.api.entity.vo.SysGoodCategoryVO;
import top.lixunda.ecommerce.server.good.config.QiNiuConfig;
import top.lixunda.ecommerce.server.good.mapper.*;
import top.lixunda.ecommerce.server.good.service.IGoodPictureService;
import top.lixunda.ecommerce.server.good.service.IGoodsService;
import top.lixunda.ecommerce.server.good.service.IQiNiuFileService;
import top.lixunda.ecommerce.server.good.service.ISubGoodService;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品表 goods 服务实现类
 * </p>
 *
 * @author Xumda
 * @since 2019-12-18
 */
@Service
public class GoodsServiceImpl extends BaseServiceImpl<GoodsMapper, GoodsDO>
        implements IGoodsService {

    private final QiNiuConfig qiNiuConfig;

    private final SubGoodMapper subGoodMapper;

    private final SysGoodCategoryMapper sysGoodCategoryMapper;

    private final GoodGroupMapper goodGroupMapper;

    private final IQiNiuFileService qiNiuFileService;

    private final IGoodPictureService goodPictureService;

    private final ISubGoodService subGoodService;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    public GoodsServiceImpl(QiNiuConfig qiNiuConfig,
                            SubGoodMapper subGoodMapper,
                            SysGoodCategoryMapper sysGoodCategoryMapper,
                            GoodGroupMapper goodGroupMapper,
                            IQiNiuFileService qiNiuFileService,
                            IGoodPictureService goodPictureService,
                            ISubGoodService subGoodService) {
        this.qiNiuConfig = qiNiuConfig;
        this.subGoodMapper = subGoodMapper;
        this.sysGoodCategoryMapper = sysGoodCategoryMapper;
        this.goodGroupMapper = goodGroupMapper;
        this.qiNiuFileService = qiNiuFileService;
        this.goodPictureService = goodPictureService;
        this.subGoodService = subGoodService;
    }

    /**
     * 根据多个id查询商品基本信息
     *
     * @param ids 商品id列表
     * @return 商品基本信息列表
     */
    @Override
    public List<GoodsDO> queryByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数ids不能为空");
        }
        List<GoodsDO> resultList;
        if (ids.size() == 1) {
            GoodsDO goodsDO = this.getOne(
                    new LambdaQueryWrapper<GoodsDO>()
                            .eq(GoodsDO::getId, ids.get(0))
                            .eq(GoodsDO::getState, GoodsDO.STATE_NORMAL), false);
            if (goodsDO == null) {
                resultList = Collections.emptyList();
            } else {
                resultList = Collections.singletonList(goodsDO);
            }
        } else {
            resultList = new ArrayList<>(this.list(new LambdaQueryWrapper<GoodsDO>()
                    .in(GoodsDO::getId, ids)
                    .eq(GoodsDO::getState, GoodsDO.STATE_NORMAL)));
        }
        return resultList;
    }

    /**
     * 条件分页查询商品
     *
     * @param pageDTO 查询条件DTO
     * @return 分页数据
     */
    @Override
    public IPage<GoodsDO> queryGoodsByPage(PageDTO<GoodsDO, GoodsQueryDTO> pageDTO) {
        return this.page(pageDTO.getPage(), pageDTO.getWrapper(
                wrapper -> wrapper.eq(GoodsDO::getState, GoodsDO.STATE_NORMAL)
        ));
    }

    /**
     * 根据id获取多个商品数据
     * 商家端调用，只能查询该店铺的商品信息
     *
     * @param ids 商品id列表
     * @return 商品列表
     */
    @Override
    public List<GoodsDO> queryByIdsStore(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数ids不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> resultList;
        if (ids.size() == 1) {
            GoodsDO goodsDO = this.getOne(
                    new LambdaQueryWrapper<GoodsDO>()
                            .eq(GoodsDO::getId, ids.get(0))
                            .eq(GoodsDO::getStoreId, cacheStore.getId()), false);
            if (goodsDO == null) {
                resultList = Collections.emptyList();
            } else {
                resultList = Collections.singletonList(goodsDO);
            }
        } else {
            resultList = new ArrayList<>(this.list(new LambdaQueryWrapper<GoodsDO>()
                    .in(GoodsDO::getId, ids)
                    .eq(GoodsDO::getStoreId, cacheStore.getId())));
        }
        return resultList;
    }

    /**
     * 根据条件筛选商品信息，需要分页
     * 商家端调用，只能查询该店铺的商品信息
     *
     * @param pageDTO 查询条件DTO
     * @return 商品列表
     */
    @Override
    public IPage<GoodsDO> queryGoodsByPageWrapperStore(
            PageDTO<GoodsDO, GoodsStoreQueryDTO> pageDTO) {
        CacheStore cacheStore = currentStoreCacheNotNull();
        return this.page(pageDTO.getPage(), pageDTO.getWrapper(
                wrapper -> wrapper.eq(GoodsDO::getStoreId, cacheStore.getId())
        ));
    }

    /**
     * 根据id获取多个商品数据
     * 管理员端调用，可以查询所有商品信息
     *
     * @param ids 商品id列表
     * @return 商品列表
     */
    @Override
    public List<GoodsDO> queryByIdsAdmin(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数ids不能为空");
        }
        List<GoodsDO> resultList;
        if (ids.size() == 1) {
            GoodsDO goodsDO = this.getById(ids.get(0));
            if (goodsDO == null) {
                resultList = Collections.emptyList();
            } else {
                resultList = Collections.singletonList(goodsDO);
            }
        } else {
            resultList = new ArrayList<>(this.listByIds(ids));
        }
        return resultList;
    }

    /**
     * 根据条件筛选商品信息，需要分页
     * 管理员端调用，可以查询所有商品信息
     *
     * @param pageDTO 查询条件DTO
     * @return 商品列表
     */
    @Override
    public IPage<GoodsDO> queryGoodsByPageWrapperAdmin(
            PageDTO<GoodsDO, GoodsAdminQueryDTO> pageDTO) {
        return this.page(pageDTO.getPage(), pageDTO.getWrapper());
    }

    /**
     * 获取用于插入的GoodsDO对象，初始化了一些参数
     *
     * @return GoodsDO
     */
    private GoodsDO getInsertGoodsDO() {
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        GoodsDO goodsDO = new GoodsDO();
        goodsDO.setCreateUserId(cacheStoreUser.getAccount())
                .setCreateUserName(cacheStoreUser.getName())
                .setUpdateUserId(cacheStoreUser.getAccount())
                .setUpdateUserName(cacheStoreUser.getName())
                .setCreateTime(localDateTime)
                .setUpdateTime(localDateTime)
                .setScoreUpdateTime(localDateTime)
                .setState(GoodsDO.STATE_CHECK_PENDING);
        return goodsDO;
    }

    /**
     * 获取用于插入的SubGoodSO对象，初始化了一些参数
     *
     * @return SubGoodDO
     */
    private SubGoodDO getInsertSubGoodDO(GoodsDO goodsDO, SubGoodInsertDTO subGoodInsertDTO) {
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        SubGoodDO subGoodDO = new SubGoodDO();
        BeanUtils.copyProperties(subGoodInsertDTO, subGoodDO);
        subGoodDO.setGoodId(goodsDO.getId())
                .setGoodName(goodsDO.getName())
                .setCreateTime(localDateTime)
                .setUpdateTime(localDateTime)
                .setCreateUserId(cacheStoreUser.getAccount())
                .setCreateUserName(cacheStoreUser.getName())
                .setUpdateUserId(cacheStoreUser.getAccount())
                .setUpdateUserName(cacheStoreUser.getName())
                .setState(SubGoodDO.STATE_NORMAL);
        return subGoodDO;
    }

    /**
     * 获取用于插入的SubGoodSO对象，初始化了一些参数
     *
     * @return SubGoodDO
     */
    private SubGoodDO getChangeSubGoodDO(GoodsDO goodsDO, SubGoodChangeDTO subGoodChangeDTO) {
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        SubGoodDO subGoodDO = new SubGoodDO();
        BeanUtils.copyProperties(subGoodChangeDTO, subGoodDO);
        if (subGoodDO.getId() == null || subGoodDO.getId() <= 0) {
            subGoodDO.setId(null);
        }
        subGoodDO.setGoodId(goodsDO.getId())
                .setGoodName(goodsDO.getName())
                .setCreateTime(localDateTime)
                .setUpdateTime(localDateTime)
                .setCreateUserId(cacheStoreUser.getAccount())
                .setCreateUserName(cacheStoreUser.getName())
                .setUpdateUserId(cacheStoreUser.getAccount())
                .setUpdateUserName(cacheStoreUser.getName())
                .setState(SubGoodDO.STATE_CHECK_PENDING);
        return subGoodDO;
    }

    /**
     * 插入商品数据
     *
     * @param goodsInsertDTO 商品数据
     * @return GoodsDO
     */
    private GoodsDO insertGoodsDO(GoodsInsertDTO goodsInsertDTO) {
        // 插入商品数据
        CacheStore cacheStore = currentStoreCacheNotNull();
        GoodsDO goodsDO = getInsertGoodsDO();
        BeanUtils.copyProperties(goodsInsertDTO, goodsDO);
        GoodGroupDO goodGroupDO = ObjectValidators.isEmpty(goodsInsertDTO.getGroupId())
                || goodsInsertDTO.getGroupId() <= 0 ?
                new GoodGroupDO() :
                goodGroupMapper.selectOne(
                        new LambdaQueryWrapper<GoodGroupDO>()
                                .select(GoodGroupDO::getId, GoodGroupDO::getName)
                                .eq(GoodGroupDO::getId, goodsInsertDTO.getGroupId())
                                .eq(GoodGroupDO::getStoreId, cacheStore.getId()));
        SysGoodCategoryDO sysGoodCategoryDO = sysGoodCategoryMapper.selectOne(
                new LambdaQueryWrapper<SysGoodCategoryDO>()
                        .select(SysGoodCategoryDO::getId, SysGoodCategoryDO::getName)
                        .eq(SysGoodCategoryDO::getId, goodsInsertDTO.getGoodCategoryId()));
        if (ObjectValidators.isEmpty(goodGroupDO)) {
            throw getAppException("商品分组不存在");
        }
        if (ObjectValidators.isEmpty(sysGoodCategoryDO)) {
            throw getAppException("商品类别不存在");
        }
        goodsDO.setStoreId(cacheStore.getId())
                .setStoreName(cacheStore.getName())
                .setGoodCategoryId(sysGoodCategoryDO.getId())
                .setGoodCategoryName(sysGoodCategoryDO.getName())
                .setGroupId(goodGroupDO.getId())
                .setGroupName(goodGroupDO.getName())
                .setRemark("测试数据");
        boolean success = this.save(goodsDO);
        if (!success) {
            log.debug("插入商品数据失败");
            throw getAppException("保存商品数据失败");
        }
        return goodsDO;
    }

    /**
     * 插入子商品信息
     *
     * @param goodsDO        商品基本信息
     * @param goodsInsertDTO 子商品信息
     * @return List<SubGoodDO>
     */
    @SuppressWarnings("UnusedReturnValue")
    private List<SubGoodDO> insertSubGoodsList(GoodsDO goodsDO, GoodsInsertDTO goodsInsertDTO) {
        LocalDateTime localDateTime = LocalDateTime.now();
        if (ObjectValidators.isEmpty(goodsInsertDTO.getSubGoodList())) {
            throw getAppException("至少包含一个子商品");
        }
        List<SubGoodDO> subInsertList = new ArrayList<>(goodsInsertDTO.getSubGoodList().size());
        SubGoodDO subGoodDO;
        for (SubGoodInsertDTO subGoodInsertDTO : goodsInsertDTO.getSubGoodList()) {
            subGoodDO = getInsertSubGoodDO(goodsDO, subGoodInsertDTO);
            subGoodDO.setCreateTime(localDateTime)
                    .setUpdateTime(localDateTime)
                    .setRemark("测试数据");
            subInsertList.add(subGoodDO);
        }
        boolean success = subGoodService.saveBatch(subInsertList);
        if (!success) {
            log.debug("插入子商品数据失败");
            throw getAppException("插入商品数据失败");
        }
        return subInsertList;
    }

    /**
     * 插入商品图片
     *
     * @param goodsDO 商品基本信息
     * @param files   将要导入的文件
     */
    private void insertGoodImage(GoodsDO goodsDO, MultipartFile[] files) {
        if (ObjectValidators.isEmpty(files)) {
            return;
        }
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<QiNiuFileDO> qiNiuFileList = new ArrayList<>(files.length);
        QiNiuCallbackBody qiNiuCallbackBody;
        for (MultipartFile file : files) {
            try {
                String name = StringUtils.randomFileName(file);
                qiNiuCallbackBody = uploadQiNiuFile(file.getInputStream(), name);
                QiNiuFileDO qiNiuFileDO = new QiNiuFileDO();
                BeanUtils.copyProperties(qiNiuCallbackBody, qiNiuFileDO);
                qiNiuFileDO.setFileKey(qiNiuCallbackBody.getKey());
                if ("null".equals(qiNiuFileDO.getParam1())) {
                    qiNiuFileDO.setParam1(null);
                }
                if ("null".equals(qiNiuFileDO.getParam2())) {
                    qiNiuFileDO.setParam2(null);
                }
                if ("null".equals(qiNiuFileDO.getParam3())) {
                    qiNiuFileDO.setParam3(null);
                }
                qiNiuFileDO.setCreateTime(localDateTime)
                        .setUserId(cacheStore.getId())
                        .setUserType(QiNiuFileDO.USER_TYPE_STORE);
                qiNiuFileList.add(qiNiuFileDO);
            } catch (IOException e) {
                e.printStackTrace();
                throw getAppException("保存图片文件失败");
            }
        }
        boolean success = qiNiuFileService.saveBatch(qiNiuFileList);
        if (!success) {
            log.error("保存文件数据信息失败");
            throw getAppException("保存数据失败");
        }
        List<GoodPictureDO> goodPictureList = new ArrayList<>(qiNiuFileList.size());
        GoodPictureDO goodPictureDO;
        for (QiNiuFileDO qiNiuFileDO : qiNiuFileList) {
            goodPictureDO = new GoodPictureDO();
            goodPictureDO.setGoodId(goodsDO.getId())
                    .setGoodName(goodsDO.getName())
                    .setImageFileId(qiNiuFileDO.getId())
                    .setImage(qiNiuConfig.getBaseUrl() + qiNiuFileDO.getFileKey())
                    .setRemark("测试数据");
            goodPictureList.add(goodPictureDO);
        }
        success = goodPictureService.saveBatch(goodPictureList);
        if (!success) {
            log.error("保存商品图片数据信息失败");
            throw getAppException("保存数据失败");
        }
    }

    /**
     * 添加商品新的商品数据
     *
     * @param files 商品图片
     * @param goodsInsertDTO 商品数据
     * @return 返回是否添加成功
     */
    @Override
    @Transactional(rollbackFor = {Throwable.class})
    public Boolean addGood(MultipartFile[] files, GoodsInsertDTO goodsInsertDTO) {
        if (ObjectValidators.isEmpty(goodsInsertDTO)) {
            throw getAppException("插入数据不能为空");
        }
        // 插入商品数据
        GoodsDO goodsDO = insertGoodsDO(goodsInsertDTO);
        // 插入子商品数据
        insertSubGoodsList(goodsDO, goodsInsertDTO);
        // 保存图片
        insertGoodImage(goodsDO, files);
        return true;
    }

    /**
     * 修改商品基本数据，即GoodsDO数据表
     *
     * @param goodsChangeDTO 商品的id及修改的数据
     */
    private GoodsDO changeGoodsDO(GoodsChangeDTO goodsChangeDTO) {
        CacheStore cacheStore = currentStoreCacheNotNull();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        GoodsDO goodsDO = this.getOne(
                new LambdaQueryWrapper<GoodsDO>()
                        .eq(GoodsDO::getStoreId, cacheStore.getId())
                        .eq(GoodsDO::getId, goodsChangeDTO.getId()), false);
        if (ObjectValidators.isEmpty(goodsDO)) {
            throw getAppException("商品不存在");
        }
        BeanUtils.copyProperties(goodsChangeDTO, goodsDO);
        if (ObjectValidators.isNotEmpty(goodsChangeDTO.getGroupId())) {
            GoodGroupDO goodGroupDO = goodGroupMapper.selectById(goodsChangeDTO.getGroupId());
            if (ObjectValidators.isEmpty(goodGroupDO)) {
                throw getAppException("商品分组不存在");
            }
            goodsDO.setGroupName(goodGroupDO.getName());
        }
        if (ObjectValidators.isNotEmpty(goodsChangeDTO.getGoodCategoryId())) {
            SysGoodCategoryDO sysGoodCategoryDO = sysGoodCategoryMapper.selectById(goodsChangeDTO.getGoodCategoryId());
            if (ObjectValidators.isEmpty(sysGoodCategoryDO)) {
                throw getAppException("商品类别不存在");
            }
            goodsDO.setGoodCategoryName(sysGoodCategoryDO.getName());
        }
        if (!goodsDO.getGoodCategoryId().equals(goodsChangeDTO.getGoodCategoryId())) {
            SysGoodCategoryDO sysGoodCategoryDO = sysGoodCategoryMapper.selectOne(
                    new LambdaQueryWrapper<SysGoodCategoryDO>()
                            .select(SysGoodCategoryDO::getId, SysGoodCategoryDO::getName)
                            .eq(SysGoodCategoryDO::getId, goodsChangeDTO.getGoodCategoryId()));
            if (ObjectValidators.isEmpty(sysGoodCategoryDO)) {
                throw getAppException("商品类别不存在");
            }
            goodsDO.setGoodCategoryId(sysGoodCategoryDO.getId())
                    .setGoodCategoryName(sysGoodCategoryDO.getName());
        }
        if (!goodsDO.getGroupId().equals(goodsChangeDTO.getGroupId())) {
            GoodGroupDO goodGroupDO = goodGroupMapper.selectOne(
                    new LambdaQueryWrapper<GoodGroupDO>()
                            .select(GoodGroupDO::getId, GoodGroupDO::getName)
                            .eq(GoodGroupDO::getId, goodsChangeDTO.getGroupId())
                            .eq(GoodGroupDO::getStoreId, cacheStore.getId()));
            if (ObjectValidators.isEmpty(goodGroupDO)) {
                throw getAppException("商品分组不存在");
            }
            goodsDO.setGroupId(goodGroupDO.getId())
                    .setGroupName(goodGroupDO.getName());
        }
        goodsDO.setUpdateTime(LocalDateTime.now())
                .setUpdateUserId(cacheStoreUser.getAccount())
                .setUpdateUserName(cacheStoreUser.getName());
        boolean success = this.updateById(goodsDO);
        if (!success) {
            throw getAppException("修改商品数据失败");
        }
        return goodsDO;
    }

    /**
     * 修改商品子商品数据
     *
     * @param goodsDO        更新后的商品基本信息
     * @param goodsChangeDTO 修改的数据信息
     */
    private void changeSubGoodDO(GoodsDO goodsDO, GoodsChangeDTO goodsChangeDTO) {
        if (ObjectValidators.isEmpty(goodsChangeDTO.getSubGoodList())) {
            return;
        }
        // 添加及修改
        LocalDateTime localDateTime = LocalDateTime.now();
        CacheStoreUser cacheStoreUser = currentStoreUserCacheNotNull();
        List<SubGoodDO> subInsertOrUpdateList = new ArrayList<>(goodsChangeDTO.getSubGoodList().size());
        SubGoodDO subGoodDO;
        boolean insert, flag;
        // 添加并鉴权
        List<SubGoodDO> oldSubGoodList = subGoodMapper.selectList(
                new LambdaQueryWrapper<SubGoodDO>()
                        .select(SubGoodDO::getId)
                        .eq(SubGoodDO::getGoodId, goodsChangeDTO.getId()));
        List<Integer> oldIds = oldSubGoodList.stream()
                .map(SubGoodDO::getId)
                .collect(Collectors.toList());
        for (SubGoodChangeDTO subGoodChangeDTO : goodsChangeDTO.getSubGoodList()) {
            insert = subGoodChangeDTO.getId() == null || subGoodChangeDTO.getId() <= 0;
            subGoodDO = insert ? getChangeSubGoodDO(goodsDO, subGoodChangeDTO) : new SubGoodDO();
            BeanUtils.copyProperties(subGoodChangeDTO, subGoodDO);
            if (insert) {
                subGoodDO.setId(null);
            } else {
                // 不是插入即为更新操作，需要验证权限
                flag = true;
                for (Integer id : oldIds) {
                    if (id.equals(subGoodDO.getId())) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    throw getAppException("子商品不存在或权限不足");
                }
            }
            subGoodDO.setUpdateTime(localDateTime)
                    .setUpdateUserId(cacheStoreUser.getAccount())
                    .setUpdateUserName(cacheStoreUser.getName());
            subInsertOrUpdateList.add(subGoodDO);
        }

        // 添加及更新数据
        boolean success = subGoodService.saveOrUpdateBatch(subInsertOrUpdateList);
        if (!success) {
            log.debug("更新子商品数据失败，执行 subGoodService.saveOrUpdateBatch 返回 false");
            throw getAppException("更新子商品数据失败");
        }

        // 移除数据
        if (ObjectValidators.isNotEmpty(goodsChangeDTO.getRemoveSubGoods())) {
            removeSubGoodsByIds(goodsChangeDTO.getRemoveSubGoods());
        }
    }

    /**
     * 修改商品图片信息
     *
     * @param goodsDO        商品数据
     * @param files          需要添加的文件
     * @param goodsChangeDTO 保存有需要移除的图片信息
     */
    private void changeGoodPicture(GoodsDO goodsDO, MultipartFile[] files, GoodsChangeDTO goodsChangeDTO) {
        // 添加图片
        if (ObjectValidators.isNotEmpty(files)) {
            insertGoodImage(goodsDO, files);
        }
        // 移除图片
        if (ObjectValidators.isNotEmpty(goodsChangeDTO.getRemoveFiles())) {
            boolean success = goodPictureService.remove(new LambdaQueryWrapper<GoodPictureDO>()
                    .eq(GoodPictureDO::getGoodId, goodsDO.getId())
                    .in(GoodPictureDO::getId, goodsChangeDTO.getRemoveFiles()));
            if (!success) {
                log.error("移除图片失败");
                throw getAppException("移除图片数据失败, 图片不存在");
            }
        }
    }

    /**
     * 修改商品信息DTO
     *
     * @param files 需要添加的商品图片
     * @param goodsChangeDTO 修改的商品数据
     * @return 是否修改成功
     */
    @Override
    @Transactional(rollbackFor = {Throwable.class})
    public Boolean changeGood(MultipartFile[] files, GoodsChangeDTO goodsChangeDTO) {
        if (ObjectValidators.isEmpty(goodsChangeDTO) || goodsChangeDTO.getId() == null) {
            throw getAppException("参数不能为空");
        }
        // 修改商品基本信息
        GoodsDO goodsDO = changeGoodsDO(goodsChangeDTO);
        // 修改子商品信息
        changeSubGoodDO(goodsDO, goodsChangeDTO);
        // 修改商品图片信息
        changeGoodPicture(goodsDO, files, goodsChangeDTO);
        return true;
    }

    /**
     * 根据id移除商品信息，店铺调用，只能移除自己店铺的商品数据
     *
     * @param ids 商品id
     * @return 是否移除成功
     */
    @Override
    @Transactional(rollbackFor = {Throwable.class})
    public Boolean removeGoodsByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数ids不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        // 查询信息，为了鉴权
        List<GoodsDO> goodList = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
        // 重组ids
        ids = goodList.stream()
                .map(GoodsDO::getId)
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("商品不存在或权限不足");
        }
        this.removeByIds(ids);
        subGoodMapper.delete(new LambdaUpdateWrapper<SubGoodDO>()
                .in(SubGoodDO::getGoodId, ids));
        return true;
    }

    /**
     * 根据子商品id列表移除子商品数据，店铺调用，只能移除自己店铺的商品数据，且移除后该商品至少包含一个子商品
     *
     * @param ids 子商品id列表
     * @return 是否移除成功
     */
    @Override
    @Transactional(rollbackFor = {Throwable.class})
    public Boolean removeSubGoodsByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数ids不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        // 查询goodIds鉴权, 拿到GoodId
        List<SubGoodDO> subGoodList = subGoodMapper.selectList(
                new LambdaQueryWrapper<SubGoodDO>()
                .in(SubGoodDO::getId, ids)
                .select(SubGoodDO::getGoodId));
        List<Integer> goodIds = subGoodList.stream()
                .distinct()
                .map(SubGoodDO::getGoodId)
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(goodIds)) {
            throw getAppException("子商品不存在");
        }
        // 鉴权，重组ids，根据goodId鉴权，获取信息goodId
        List<GoodsDO> goodList = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, goodIds));
        goodIds = goodList.stream()
                .distinct()
                .map(GoodsDO::getId)
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(goodIds)) {
            throw getAppException("商品不存在或权限不足");
        }
        // 根据参数ids和goodIds删除数据
        subGoodMapper.delete(new LambdaUpdateWrapper<SubGoodDO>()
                .in(SubGoodDO::getId, ids)
                .in(SubGoodDO::getGoodId, goodIds));
        // 校验，至少包含一个subGood
        List<SubGoodDO> list = subGoodMapper.selectList(new LambdaQueryWrapper<SubGoodDO>()
                .in(SubGoodDO::getGoodId, goodIds)
                .select(SubGoodDO::getId, SubGoodDO::getGoodName))
                .stream()
                .distinct()
                .collect(Collectors.toList());
        if (list.size() < goodIds.size()) {
            throw getAppException("删除子商品失败，商品至少含有一个子分类商品");
        }
        return true;
    }

    /**
     * 店铺调用，查询当前店铺中商品的所有Category信息
     *
     * @return List SysGoodCategoryVO
     */
    @Override
    public List<SysGoodCategoryVO> queryStoreGoodCategory() {
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .select(GoodsDO::getGoodCategoryId, GoodsDO::getGoodCategoryName));
        return list.stream()
                .distinct()
                .map(item -> {
                    SysGoodCategoryVO vo = new SysGoodCategoryVO();
                    vo.setId(item.getGoodCategoryId())
                            .setName(item.getGoodCategoryName());
                    return vo;
                })
                .collect(Collectors.toList());
    }

    /**
     * 店铺调用，查询当前店铺中商品的所有Group信息
     *
     * @return List<SysGoodCategoryVO>
     */
    @Override
    public List<GoodGroupVO> queryStoreGoodGroup() {
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .select(GoodsDO::getGroupId, GoodsDO::getGroupName));
        return list.stream()
                .distinct()
                .map(item -> {
                    GoodGroupVO vo = new GoodGroupVO();
                    vo.setId(item.getGroupId())
                            .setName(item.getGroupName());
                    return vo;
                })
                .collect(Collectors.toList());
    }

    /**
     * 店铺调用，查询当前店铺中商品的所有SellPoint信息
     *
     * @return List<SysGoodCategoryVO>
     */
    @Override
    public List<String> queryStoreGoodSellPoint() {
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .select(GoodsDO::getSellPoint));
        return list.stream()
                .distinct()
                .map(GoodsDO::getSellPoint)
                .collect(Collectors.toList());
    }

    /**
     * 店铺调用，查询当前店铺中商品的所有Freight信息
     *
     * @return List<SysGoodCategoryVO>
     */
    @Override
    public List<BigDecimal> queryStoreGoodFreight() {
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .select(GoodsDO::getFreight));
        return list.stream()
                .distinct()
                .map(GoodsDO::getFreight)
                .collect(Collectors.toList());
    }

    /**
     * 店铺调用，查询当前店铺中商品的部分信息筛选项
     *
     * @return Map String,List
     */
    @Override
    public Map<String, Set> queryStoreGoodTableFilter() {
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .select(GoodsDO::getGoodCategoryId, GoodsDO::getGoodCategoryName,
                        GoodsDO::getGroupId, GoodsDO::getGroupName,
                        GoodsDO::getSellPoint, GoodsDO::getFreight));
        Set<SysGoodCategoryVO> categoryList = new HashSet<>(list.size() / 4);
        Set<GoodGroupVO> goodGroupList = new HashSet<>(list.size() / 4);
        Set<String> sellPointList = new HashSet<>(list.size() / 4);
        Set<BigDecimal> freightList = new HashSet<>(list.size() / 4);
        list.forEach(item -> {
            categoryList.add(new SysGoodCategoryVO()
                    .setId(item.getGoodCategoryId())
                    .setName(item.getGoodCategoryName()));
            goodGroupList.add(new GoodGroupVO()
                    .setId(item.getGroupId())
                    .setName(item.getGroupName()));
            sellPointList.add(item.getSellPoint());
            freightList.add(item.getFreight());
        });
        Map<String, Set> map = new HashMap<>(4);
        map.put("category", categoryList);
        map.put("group", goodGroupList);
        map.put("sellPoint", sellPointList);
        map.put("freight", freightList);
        return map;
    }

    /**
     * 店铺调用，提交商品进行审核
     *
     * @param ids 商品数据id列表
     * @return 是否提交申请成功
     */
    @Override
    public Boolean pushGoodsCheckPending(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
        if (ObjectValidators.isEmpty(list) || list.size() < ids.size()) {
            throw getAppException("部分商品不存在");
        }
        list.forEach(item -> {
            if (!GoodsDO.STATE_CHECK_PENDING.equals(item.getState())) {
                throw getAppException("只有待审核的数据可以提交审核");
            }
        });
        return this.update(new LambdaUpdateWrapper<GoodsDO>()
                .set(GoodsDO::getState, GoodsDO.STATE_CHECKING)
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
    }

    /**
     * 店铺调用，取消提交的商品审核
     *
     * @param ids 商品数据id列表
     * @return 是否成功取消
     */
    @Override
    public Boolean cancelGoodsCheckPending(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
        if (ObjectValidators.isEmpty(list) || list.size() < ids.size()) {
            throw getAppException("部分商品不存在");
        }
        list.forEach(item -> {
            if (!GoodsDO.STATE_CHECKING.equals(item.getState())) {
                throw getAppException("部分商品不存在审核中的信息");
            }
        });
        return this.update(new LambdaUpdateWrapper<GoodsDO>()
                .set(GoodsDO::getState, GoodsDO.STATE_CHECK_PENDING)
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
    }

    /**
     * 店铺调用，上架商品
     *
     * @param ids 商品数据id列表
     * @return 是否上架成功
     */
    @Override
    public Boolean pushGoods(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
        if (ObjectValidators.isEmpty(list) || list.size() < ids.size()) {
            throw getAppException("部分商品不存在");
        }
        list.forEach(item -> {
            if (!GoodsDO.STATE_NOT_ON.equals(item.getState())) {
                throw getAppException("部分商品处于上架状态或不能上架");
            }
        });
        return this.update(new LambdaUpdateWrapper<GoodsDO>()
                .set(GoodsDO::getState, GoodsDO.STATE_NORMAL)
                .set(GoodsDO::getPushTime, LocalDateTime.now())
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
    }

    /**
     * 店铺调用，下架商品
     *
     * @param ids 商品数据id列表
     * @return 是否下架成功
     */
    @Override
    public Boolean pullGoods(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("参数不能为空");
        }
        CacheStore cacheStore = currentStoreCacheNotNull();
        List<GoodsDO> list = this.list(new LambdaQueryWrapper<GoodsDO>()
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
        if (ObjectValidators.isEmpty(list) || list.size() < ids.size()) {
            throw getAppException("部分商品不存在");
        }
        list.forEach(item -> {
            if (!GoodsDO.STATE_NORMAL.equals(item.getState())) {
                throw getAppException("部分商品未上架");
            }
        });
        return this.update(new LambdaUpdateWrapper<GoodsDO>()
                .set(GoodsDO::getState, GoodsDO.STATE_NOT_ON)
                .set(GoodsDO::getPullTime, LocalDateTime.now())
                .eq(GoodsDO::getStoreId, cacheStore.getId())
                .in(GoodsDO::getId, ids));
    }

    /**
     * 管理员调用，审核添加的商品
     *
     * @param list 审核数据信息
     * @return 审核结果
     */
    @Override
    public Boolean checkingGoods(List<AdminCheckingDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("参数不能为空");
        }
        CacheAdminUser cacheAdminUser = currentAdminUserCacheNotNull();
        List<Integer> ids = list.stream()
                .map(AdminCheckingDTO::getId)
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(ids) || ids.size() < list.size()) {
            throw getAppException("参数错误");
        }
        List<GoodsDO> goodList = this.list(new LambdaQueryWrapper<GoodsDO>()
                .in(GoodsDO::getId, ids));
        if (ObjectValidators.isEmpty(goodList) || goodList.size() < ids.size()) {
            throw getAppException("部分商品不存在");
        }
        goodList.forEach(item -> {
            if (!GoodsDO.STATE_CHECKING.equals(item.getState())) {
                throw getAppException("商品审核申请不存在");
            }
        });
        LocalDateTime localDateTime = LocalDateTime.now();
        List<GoodsDO> updateGoods = list.stream()
                .map(item -> {
                    GoodsDO goodsDO = new GoodsDO();
                    goodsDO.setId(item.getId())
                            .setStateDesc(item.getMessage())
                            .setCheckTime(localDateTime)
                            .setCheckUserId(cacheAdminUser.getAccount())
                            .setCheckUserName(cacheAdminUser.getName())
                            .setState(item.getSuccess() ?
                                    GoodsDO.STATE_NOT_ON : GoodsDO.STATE_FAILED);
                    return goodsDO;
                })
                .collect(Collectors.toList());
        return this.updateBatchById(updateGoods);
    }

}
